package vcp.application;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;

import vcp.gui.utils.*;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.Observable;
import java.util.Observer;
import java.util.Properties;

import javax.imageio.ImageIO;
import javax.print.DocFlavor.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JOptionPane;

import client.Message;
import control.SimpleClient;
import db.parking.beans.Employee;
import vcp.app.utils.*;
import vcp.controllers.CheckInController;
import vcp.controllers.CheckOutController;
import vcp.controllers.ComplaintController;
import vcp.controllers.CustomerContactController;
import vcp.controllers.LoginController;
import vcp.controllers.OrdersGuestController;
import vcp.controllers.ResolveComplaintsController;
import vcp.controllers.SaveParkingController;
import vcp.controllers.SubscriptionController;
import vcp.gui.components.VCPFrame;
import vcp.gui.components.VCPMenu;
import vcp.gui.components.VCPPanel;
import vcp.gui.forms.CheckInWidgetForm;
import vcp.gui.forms.CheckOutForm;
import vcp.gui.forms.LoginForm;
import vcp.gui.panels.ImagePanel;
import vcp.gui.panels.TopMainScreen;
import vcp.gui.panels.pnlCustomerServiceMenu;
import vcp.gui.panels.pnlGuestMenu;
import vcp.gui.panels.pnlNetworkManagerMenu;
import vcp.gui.panels.pnlParkingManagerMenu;
import vcp.gui.panels.pnlParkingWorkerMenu;
import vcp.gui.utils.MenuBuilder;
import vcp.models.CheckInModel;
import vcp.models.CheckOutModel;
import vcp.models.ComplaintsModel;
import vcp.models.CustomerContactModel;
import vcp.models.LoginModel;
import vcp.models.OrdersCancelOrderModel;
import vcp.models.OrdersModel;
import vcp.models.OrdersOccasionalOrderModel;
import vcp.models.OrdersSubscriptionModel;
import vcp.models.OrdersTemporaryModel;
import vcp.models.OrdersTrackModel;
import vcp.models.ResolveComplaintsModel;
import vcp.models.SaveParkingModel;
import vcp.models.SubscriptionModelFull;
import vcp.models.SubscriptionModelRegular;
import vcp.test.entities.User;
import vcp.views.CheckInView;
import vcp.views.CheckOutView;
import vcp.views.ComplaintsView;
import vcp.views.CustomerContactView;
import vcp.views.LoginView;
import vcp.views.OrderGuestView;
import vcp.views.ResolveComplaintsView;
import vcp.views.SubscriptionView;

/* listen for loader observable */
public class Bootstrapper implements Observer {

	private Settings s;

	private VCPFrame mainFrame;
	private VCPPanel mainPanel;

	private OrdersModel ordersGuestModel;
	private OrderGuestView ordersGuestview;
	private OrdersGuestController ordersGuestController;
	private OrdersCancelOrderModel ordersCancelOrderModel;
	private OrdersOccasionalOrderModel ordersOccasionalOrderModel;
	private OrdersSubscriptionModel ordersSubscriptionModel;
	private OrdersTemporaryModel ordersTemporaryModel;
	private OrdersTrackModel ordersTrackModel;
	private LoginView loginView;
	private LoginModel loginModel;
	private LoginController loginController;

	private GuestView guestView;

	private SimpleClient client;

	private int _projectWidth = Integer.parseInt((getSettings()
			.getProperty("ProjectWidth")));
	private int _projectHeight = Integer.parseInt((getSettings()
			.getProperty("ProjectHeight")));
	private int _menuSidebarWidth = Integer.parseInt((getSettings()
			.getProperty("MenuSidebarWidth")));
	private int _menuSidebarHeight = Integer.parseInt((getSettings()
			.getProperty("MenuSidebarHeight")));
	private TopMainScreen topScreen;

	private VCPPanel pnlLeft;
	private VCPPanel pnlRight;
	private VCPPanel pnlSwitch;

	private SubscriptionView subscriptionView;
	private SubscriptionController subscriptionController;
	private SubscriptionModelFull subscriptionModel1;
	private SubscriptionModelRegular subscriptionModel2;

	private UserView userView;

	private VCPPanel userPanel;

	private SaveParkingModel saveParkingModel;

	private SaveParkingController saveParkingController;

	private ComplaintsModel complaintsModel;

	private ComplaintsView complaintsView;

	private ComplaintController complaintsController;

	private CustomerContactController customerContactController;

	private CustomerContactModel customerContactModel;

	private CustomerContactView customerContactView;

	private ResolveComplaintsController resolveComplaintsController;

	private ResolveComplaintsView resolveComplaintsView;

	private ResolveComplaintsModel resolveComplaintsModel;

	private CheckInModel checkInModel;

	private CheckInView checkInView;

	private CheckInController checkInController;

	private CheckOutModel checkOutModel;

	private CheckOutView checkOutView;

	private CheckOutController checkOutController;

	public Bootstrapper() {
		AppInit();
	}

	// here is actual login based on user properties:
	@Override
	public void update(Observable o, Object arg) {
		Employee emp = null;
		Message mess = (Message) arg;
		if (mess.getStatusMsg().equals("OK")) {
			emp = (Employee) mess.getObj();
			initUserView(emp);
		}else{
			JOptionPane.showMessageDialog(null,mess.getStatusMsg().toString(),null, JOptionPane.ERROR_MESSAGE);
		}
		// System.out.println(emp.getEmpName());
		// if (emp != null) {
		// System.out.println("entered");
		// initUserView(emp);
		// }
	}

	/* app starts here */
	private void AppInit() {
		initClient();
		initControllers();
		initGuestView();
		mainFrame = getMainFrame();
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		File file = new File("img/vcp.jpg");
		mainFrame.setIconImage(toolkit.getImage(file.getAbsolutePath()));

		mainFrame.addWindowListener(new CloseListener());
		mainFrame.setVisible(true);
	}

	/* end */

	private void initGuestView() {
		guestView = new GuestView();
	}

	private void initUserView(Employee emp) {
		userView = new UserView(emp);
	}

	public Properties getSettings() {
		if (s == null)
			s = new Settings();
		return s.getProperties();
	}

	/* Client */
	private void initClient() {
		if (client == null) {
			client.initClient("localhost", 12345);
			client = client.getInstance();
			open();
		}
	}

	public void close() {
		try {
			// TODO: add set host and port?
			client.closeConnection();
		} catch (Exception ex) {
			System.out.println(ex.toString());

		}
	}

	public void open() {
		try {
			client.openConnection();
		} catch (Exception ex) {
			System.out.println(ex.toString());
		}
	}

	/* End Client */

	private void initControllers() {
		/* orders instance */
		ordersGuestModel = new OrdersModel();
		ordersCancelOrderModel = new OrdersCancelOrderModel();
		ordersOccasionalOrderModel = new OrdersOccasionalOrderModel();
		ordersSubscriptionModel = new OrdersSubscriptionModel();
		ordersTemporaryModel = new OrdersTemporaryModel();
		ordersTrackModel = new OrdersTrackModel();
		ordersGuestview = new OrderGuestView();
		ordersGuestController = new OrdersGuestController();

		/* subscriptions instance */
		subscriptionView = new SubscriptionView();
		subscriptionController = new SubscriptionController();
		subscriptionModel1 = new SubscriptionModelFull();
		subscriptionModel2 = new SubscriptionModelRegular();

		/* logins instance */
		loginView = new LoginView();
		loginModel = new LoginModel();
		loginController = new LoginController();

		/* mod orders */
		ordersOccasionalOrderModel.addObserver(ordersGuestview
				.getOrderOccasionalViewForm());
		ordersSubscriptionModel.addObserver(ordersGuestview
				.getOrderSubscriptionForm());
		ordersTemporaryModel.addObserver(ordersGuestview
				.getOrderTemporaryViewForm());
		ordersCancelOrderModel.addObserver(ordersGuestview
				.getCancelOrderViewForm());
		ordersTrackModel.addObserver(ordersGuestview.getOrderTrackViewForm());

		ordersGuestController.addModel("ordersGuestModel", ordersGuestModel);
		ordersGuestController.addModel("ordersCancelOrderModel",
				ordersCancelOrderModel);
		ordersGuestController.addModel("ordersOccasionalOrderModel",
				ordersOccasionalOrderModel);
		ordersGuestController.addModel("ordersSubscriptionModel",
				ordersSubscriptionModel);
		ordersGuestController.addModel("ordersTemporaryModel",
				ordersTemporaryModel);
		ordersGuestController.addModel("ordersCancelOrderModel",
				ordersCancelOrderModel);
		ordersGuestController.addModel("ordersTrackModel", ordersTrackModel);
		ordersGuestController.addView(ordersGuestview);
		ordersGuestview.addController(ordersGuestController);

		/* mod subscriptions */
		subscriptionModel1.addObserver(subscriptionView.getSubscriptionForm1());
		subscriptionModel2.addObserver(subscriptionView.getSubscriptionForm2());
		subscriptionController.addModel1(subscriptionModel1);
		subscriptionController.addModel2(subscriptionModel2);
		subscriptionController.addView(subscriptionView);
		subscriptionView.addController(subscriptionController);

		/* mod login */
		//loginModel.addObserver(loginView);
		loginModel.addObserver(this);
		loginController.addModel(loginModel);
		loginController.addView(loginView);
		loginView.addController(loginController);

		/* check in mod */
		checkInModel = new CheckInModel();
		checkInView = new CheckInView();
		checkInController = new CheckInController();

		checkInModel.addObserver(checkInView);
		checkInController.addModel(checkInModel);
		checkInController.addView(checkInView);
		checkInView.addController(checkInController);

		/* check out mod */
		checkOutModel = new CheckOutModel();
		checkOutView = new CheckOutView();
		checkOutController = new CheckOutController();

		checkOutModel.addObserver(checkOutView);
		checkOutController.addModel(checkOutModel);
		checkOutController.addView(checkOutView);
		checkOutView.addController(checkOutController);

		/*
		 * saveParkingModel = new SaveParkingModel(); saveParkingView = new
		 * SaveParkingView(); saveParkingController = new
		 * SaveParkingController();
		 * 
		 * saveParkingModel.addObserver(saveParkingView);
		 * saveParkingController.addModel(saveParkingModel);
		 * saveParkingController.addView(saveParkingView);
		 * saveParkingView.addController(saveParkingController);
		 */
		complaintsController = new ComplaintController();
		complaintsModel = new ComplaintsModel();
		complaintsView = new ComplaintsView();

		complaintsModel.addObserver(complaintsView);
		complaintsController.addModel(complaintsModel);
		complaintsController.addView(complaintsView);
		complaintsView.addController(complaintsController);

		/* contact customer */
		customerContactController = new CustomerContactController();
		customerContactModel = new CustomerContactModel();
		customerContactView = new CustomerContactView();

		customerContactModel.addObserver(customerContactView);
		customerContactController.addModel(customerContactModel);
		customerContactController.addView(customerContactView);
		customerContactView.addController(customerContactController);

		/* resolve complaints */
		resolveComplaintsController = new ResolveComplaintsController();
		resolveComplaintsView = new ResolveComplaintsView();
		resolveComplaintsModel = new ResolveComplaintsModel();

		resolveComplaintsModel.addObserver(resolveComplaintsView);
		resolveComplaintsController.addModel(resolveComplaintsModel);
		resolveComplaintsController.addView(resolveComplaintsView);

		resolveComplaintsView.addController(resolveComplaintsController);

	}

	private class CloseListener extends WindowAdapter {
		public void windowClosing(WindowEvent e) {
			e.getWindow().setVisible(false);
			System.exit(0);
		}
	}

	/* inner classes guest view */
	private class GuestView implements ActionListener {
		private LoginForm loginForm;
		private pnlGuestMenu guestMenu;
		private CheckOutForm checkOutForm;

		public GuestView() {

			refreshPanes();

			topScreen = this.getTopScreen(null);
			loginForm = loginView.getLoginForm();
			checkOutForm = checkOutView.getForm();
			guestMenu = new pnlGuestMenu();

			guestMenu.getBtnNewOrder().addActionListener((ActionListener) this);
			guestMenu.getBtnNewOrder().setActionCommand("MenuItmNewOrder");

			guestMenu.getBtnCancelOrder().addActionListener(
					(ActionListener) this);
			guestMenu.getBtnCancelOrder()
					.setActionCommand("MenuItmCanellOrder");

			guestMenu.getBtnComplaints().addActionListener(
					(ActionListener) this);
			guestMenu.getBtnComplaints().setActionCommand("MenuItmComplaint");

			guestMenu.getBtnTrackOrder().addActionListener(
					(ActionListener) this);
			guestMenu.getBtnTrackOrder().setActionCommand("MenuItmTrackOrder");

			guestMenu.getBtnCheckIn().addActionListener((ActionListener) this);
			guestMenu.getBtnCheckIn().setActionCommand("MenuItmCheckIn");

			guestMenu.getBtnComplaints().setActionCommand("MenuItmComplaints");

			mainFrame = getMainFrame();

			mainPanel.setPreferredSize(new Dimension(_projectWidth,
					_projectHeight));

			mainPanel.setLayout(new BorderLayout());

			mainPanel.add(topScreen, BorderLayout.PAGE_START);
			pnlSwitch.setLayout(new BorderLayout());
			pnlSwitch.add(loginForm, BorderLayout.PAGE_START);
			pnlSwitch.add(checkOutForm, BorderLayout.CENTER);

			pnlLeft.setPreferredSize(new Dimension(_menuSidebarWidth,
					_menuSidebarHeight));
			Color cdblue = Color.decode("#79BEDB");

			pnlLeft.setBackground(cdblue);
			pnlLeft.add(guestMenu);

			pnlRight.setBackground(Color.white);
			pnlRight.setLayout(new BorderLayout());
			pnlRight.add(pnlSwitch, BorderLayout.CENTER);

			mainPanel.add(pnlLeft, BorderLayout.LINE_START);
			mainPanel.add(pnlRight, BorderLayout.CENTER);
			mainFrame.setContentPane(mainPanel);
			mainFrame.pack();
		}

		public TopMainScreen getTopScreen(String u) {
			if (topScreen == null) {
				topScreen = new TopMainScreen(u);
				topScreen.getBtnSubscribe().addActionListener(this);
				topScreen.getBtnSubscribe()
						.setActionCommand("TopMenuSubscribe");
				topScreen.getBtnLogin().addActionListener(this);
				topScreen.getBtnLogin().setActionCommand("TopMenuLogin");
			}
			return topScreen;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			pnlSwitch.removeAll();
			if (e.getActionCommand().equals("MenuItmNewOrder"))
				pnlSwitch.add(ordersGuestview.getWidgetPanel());
			else if (e.getActionCommand().equals("MenuItmCanellOrder"))
				pnlSwitch.add(ordersGuestview.getCancelOrderViewForm());
			else if (e.getActionCommand().equals("MenuItmTrackOrder"))
				pnlSwitch.add(ordersGuestview.getOrderTrackViewForm());
			else if (e.getActionCommand().equals("TopMenuSubscribe"))
				pnlSwitch.add(subscriptionView.getWrappedPane());
			else if (e.getActionCommand().equals("TopMenuLogin"))
				pnlSwitch.add(loginView.getLoginForm());

			else if (e.getActionCommand().equals("MenuItmCheckIn"))
				pnlSwitch.add(checkInView.getForm());

			/*
			 * else if (e.getActionCommand().equals("MenuItmSaveParking"))
			 * pnlSwitch.add(saveParkingView.getForm());
			 */
			else if (e.getActionCommand().equals("MenuItmComplaints"))
				pnlSwitch.add(complaintsView.getComplaintsForm());

			pnlSwitch.revalidate();
			pnlSwitch.repaint();
			getMainFrame().pack();

		}
	}

	private class UserView implements ActionListener {
		private pnlParkingManagerMenu parkingManagerMenu;
		private pnlCustomerServiceMenu customerServiceMenu;
		private Employee emp = null;
		private pnlParkingWorkerMenu parkingWorkerMenu;
		private pnlNetworkManagerMenu directorMenu;

		public UserView(Employee emp) {
			this.emp = emp;
			refreshPanes();
			String role = this.emp.getType();
			if (!role.equals(null)) {
				if (role.equals("PWorker")) {
					loadPWorker();
				} else if (role.equals("CSWorker")) {
					loadCSWorker();
				} else if (role.equals("PManager")) {
					loadPManager();
				}else if (role.equals("Director")) {
					loadDirector();
				}

				pnlRight.add(pnlSwitch, BorderLayout.CENTER);

				userPanel = getUserPanel();
				mainFrame = getMainFrame();

				userPanel.setPreferredSize(new Dimension(_projectWidth,
						_projectHeight));

				userPanel.setLayout(new BorderLayout());
				userPanel.add(topScreen, BorderLayout.PAGE_START);
				userPanel.add(pnlLeft, BorderLayout.LINE_START);
				userPanel.add(pnlRight, BorderLayout.CENTER);
				mainFrame.setContentPane(userPanel);
				mainFrame.pack();
			}
		}

		private void loadDirector() {
			directorMenu = new pnlNetworkManagerMenu();
			pnlLeft.add(directorMenu);
			//ImagePanel ipnl = new ImagePanel("img/peeng.jpg");

			//pnlSwitch.add(ipnl, BorderLayout.CENTER);
			//pnlSwitch.repaint();

			topScreen = this.getTopScreen("Network Manager");
		}

		private void loadPManager() {
			parkingManagerMenu = new pnlParkingManagerMenu();
			pnlLeft.add(parkingManagerMenu);
			//ImagePanel ipnl = new ImagePanel("img/peeng.jpg");

			//pnlSwitch.add(ipnl, BorderLayout.CENTER);
			//pnlSwitch.repaint();

			topScreen = this.getTopScreen("Parking Manager");
		}

		public void loadPWorker() {
			parkingWorkerMenu = new pnlParkingWorkerMenu();
			pnlLeft.add(parkingWorkerMenu);			
			//ImagePanel ipnl = new ImagePanel("img/peeng.jpg");
			//pnlSwitch.add(ipnl, BorderLayout.CENTER);
			//pnlSwitch.repaint();
			topScreen = this.getTopScreen("Customer Service");
		}

		public void loadCSWorker() {
			customerServiceMenu = new pnlCustomerServiceMenu();
			pnlLeft.add(customerServiceMenu);
			customerServiceMenu.getBtnContact().addActionListener(this);
			customerServiceMenu.getBtnContact().setActionCommand(
					"ContactCustomer");
			customerServiceMenu.getBtnResolveComplaints().addActionListener(
					this);
			customerServiceMenu.getBtnResolveComplaints().setActionCommand(
					"ResolveComplaints");
			ImagePanel ipnl = new ImagePanel("img/peeng.jpg");

			pnlSwitch.add(ipnl, BorderLayout.CENTER);
			pnlSwitch.repaint();

			topScreen = this.getTopScreen("Customer Service");

		}

		public TopMainScreen getTopScreen(String role) {
			if (topScreen == null) {
				topScreen = new TopMainScreen(role);
				topScreen.getBtnLogout().addActionListener(this);
				topScreen.getBtnLogout().setActionCommand("TopMenuLogout");
			}
			return topScreen;
		}

		@Override
		public void actionPerformed(ActionEvent eve) {
			pnlSwitch.removeAll();
			if (eve.getActionCommand().equals("TopMenuLogout")) {
				initGuestView();
			} else if (eve.getActionCommand().equals("ContactCustomer")) {
				pnlSwitch.add(customerContactView.getCustomerContactForm());
			} else if (eve.getActionCommand().equals("ResolveComplaints")) {
				pnlSwitch.add(resolveComplaintsView.getComplaintsForm());
			}
			pnlSwitch.revalidate();
			pnlSwitch.repaint();
			getMainFrame().pack();
		}
	}

	protected VCPFrame getMainFrame() {
		if (mainFrame == null) {
			mainFrame = new VCPFrame(getSettings().getProperty(
					"ApplicationTitle"));
		}
		return mainFrame;
	}

	protected VCPPanel getMainPanel() {
		if (mainPanel == null) {
			mainPanel = new VCPPanel();
		}
		return mainPanel;
	}

	protected VCPPanel getUserPanel() {
		if (userPanel == null) {
			userPanel = new VCPPanel();
		}
		return userPanel;
	}

	private VCPPanel getLeftPane() {
		if (pnlLeft == null) {
			pnlLeft = new VCPPanel();
		}
		return pnlLeft;
	}

	private VCPPanel getRightPane() {
		if (pnlRight == null) {
			pnlRight = new VCPPanel();
		}
		return pnlRight;
	}

	private VCPPanel getSwitchPane() {
		if (pnlSwitch == null) {
			pnlSwitch = new VCPPanel();
		}
		return pnlSwitch;
	}

	public void refreshPanes() {
		mainPanel = getMainPanel();
		mainPanel.removeAll();
		mainPanel.revalidate();
		mainPanel.repaint();
		userPanel = getMainPanel();
		userPanel.removeAll();
		userPanel.revalidate();
		userPanel.repaint();
		pnlLeft = getLeftPane();
		pnlLeft.removeAll();
		pnlLeft.revalidate();
		pnlLeft.repaint();
		pnlRight = getRightPane();
		pnlRight.removeAll();
		pnlRight.revalidate();
		pnlRight.repaint();
		pnlSwitch = getSwitchPane();
		pnlSwitch.removeAll();
		pnlSwitch.revalidate();
		pnlSwitch.repaint();
		topScreen = null;
	}

}
